package instructions;

import expressions.BadExpressionException;
import expressions.Expression;
import values.Value;
import base.AST;
import base.Environment;
import base.Identifier;
import base.Interpreter;

public class VariableAssign implements Instruction {

	private Identifier identifier;
	private AST expression;
	
	/**
	 * creates the instruction
	 * name = expression
	 */
	public VariableAssign(Identifier name, AST expression) {
		assert name instanceof Identifier;
		assert expression instanceof Value || expression instanceof Expression;
		
		this.identifier = name;
		this.expression = expression;
	}
	
	/**
	 * Changes the value of the identifier in the environment to the value of the expression
	 */
	public Environment instr(Environment env) throws BadInstructionException {
		assert env.contains(this.identifier);
		
		Value newValue; Environment newEnv = env.clone();
		
		try {
			newValue = Interpreter.getBoolean(expression, env);
		} catch (BadExpressionException e1) {
			try {
				newValue = Interpreter.getInt(expression, env);
			} catch (BadExpressionException e2) {
				try {
					newValue = Interpreter.getArray(expression, env);
				} catch (BadExpressionException e3) {
					try {
						newValue = Interpreter.getString(expression,
								env);
					} catch (BadExpressionException e4) {
						throw new BadInstructionException(
								"Trying to assign a non-boolean, non-integer, non-array or non-string to the variable "
										+ this.identifier.getName());
					}
				}
			}
		}
		
		newEnv.update(this.identifier, newValue);
		
		return newEnv;
	}

	
}
